#include "Defs.h"
#include "Log.h"
#include "Utils.h"

Log_T::Log_T(const char * szFilename)
	:_filePtr(0)
{
	FillMemory(&_date, sizeof(_date), 0);

	FillMemory(_szFilename, sizeof(_szFilename), 0);
	_snprintf(_szFilename, sizeof(_szFilename) - 1, szFilename);
}

Log_T::~Log_T()
{
	if( _filePtr )
	{
		delete _filePtr;
	}
}

void Log_T::Write(const char * sz)
{
	Open();

	_cs.Enter();
	_filePtr->Write(sz);
	_cs.Leave();
}

void Log_T::Write(const Session_T & session, Request_T & request, const char * szRulesName, const Error_T & err)
{
	Open();

	_cs.Enter();
	WriteDate();
	WriteSession(session);
	_filePtr->Write(" [");
	_filePtr->Write(szRulesName);
	_filePtr->Write("]");
	WriteError(err);
	WriteRequest(request);
	_filePtr->Write("\r\n");
	_cs.Leave();
}

void Log_T::Open()
{
	char szNewFilename[MAX_PATH];
	SYSTEMTIME currentTime;

	// 
	// Check if log file must be created
	//

	_timer.GetCurrent(currentTime);
	
	if( (currentTime.wDay == _date.wDay) &&
		(currentTime.wMonth == _date.wMonth) &&
		(currentTime.wYear == _date.wYear) )
	{
		return;
	}

	//
	// Set log file date
	//

	_timer.GetCurrent(_date);

	// 
	// Initialize log filename format
	//
	
	_snprintf(szNewFilename, sizeof(szNewFilename) - 1, LOG_FILENAME, 
		_szFilename,
		_date.wYear,
		_date.wMonth,
		_date.wDay,
		GetCurrentProcessId());

	//
	// Create parent directories for log files directory
	//
	
	Utils_T::CreateParentDirs(szNewFilename);

	// 
	// Close current log file (if open)
	// Open log file
	//

	if( _filePtr )
	{
		delete _filePtr;
		_filePtr = 0;
	}

	_filePtr = new File_T(szNewFilename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_ALWAYS, true);

	//
	// Write initialization data
	//

	char szBuffer[8192];
	_snprintf(szBuffer, sizeof(szBuffer) - 1, LOG_TEMPLATE,
		_date.wYear,
		_date.wMonth,
		_date.wDay,
		_date.wHour,
		_date.wMinute,
		_date.wSecond);

	_filePtr->Write(szBuffer);
}

void Log_T::WriteDate()
{
	SYSTEMTIME currentTime;
	_timer.GetCurrent(currentTime);
	
	char szDateTime[50];
	FillMemory(szDateTime, sizeof(szDateTime), 0);

	_snprintf(szDateTime, sizeof(szDateTime) - 1, "[%04d-%02d-%02d] [%02d:%02d:%02d:%03d]",
		currentTime.wYear,
		currentTime.wMonth,
		currentTime.wDay,
		currentTime.wHour,
		currentTime.wMinute,
		currentTime.wSecond,
		currentTime.wMilliseconds);
	_filePtr->Write(szDateTime);
}

void Log_T::WriteError(const Error_T & err)
{
	char szText[8192];

	_filePtr->Write(" [");
	_filePtr->Write(err.ToString());
	_filePtr->Write("]");
	
	if( Error_T::ERR_WINDOWS == err.Code() )
	{
		_snprintf(szText, sizeof(szText) - 1, " [%d]", err.WinErr());
	}
	else
	{
		_snprintf(szText, sizeof(szText) - 1, " [-]");
	}

	_filePtr->Write(szText);
}

void Log_T::WriteSession(const Session_T & session)
{
	_filePtr->Write(" [");
	_filePtr->Write(session.remoteAddr.Ptr());
	_filePtr->Write("] [");
	_filePtr->Write(session.remotePort.Ptr());
	_filePtr->Write("] [");
	_filePtr->Write(session.localAddr.Ptr());
	_filePtr->Write("] [");
	_filePtr->Write(session.serverPort.Ptr());
	_filePtr->Write("]");
}

void Log_T::WriteRequest(Request_T & request)
{
	_filePtr->Write(" [");
	_filePtr->Write(request.Verb().Ptr(), request.Verb().Length());
	_filePtr->Write(" ");
	_filePtr->Write(request.Uri().Ptr(), request.Uri().Length());
	_filePtr->Write(" ");
	_filePtr->Write(request.Version().Ptr(), request.Version().Length());
	_filePtr->Write("]");
}

//
// Static Members
//

List_T<Log_T> * Log_T::s_logListPtr = 0;

void Log_T::Load()
{
	s_logListPtr = new List_T<Log_T>();
}

Log_T * Log_T::Load(const char * szFilename)
{
	for( unsigned int ix = 0 ; ix < s_logListPtr->Count() ; ix++ )
	{
		if( String_T(s_logListPtr->operator[](ix)->_szFilename).Equals(szFilename, false) )
		{
			return s_logListPtr->operator[](ix);
		}
	}

	return s_logListPtr->Add(new Log_T(szFilename));
}

void Log_T::Unload()
{
	if( s_logListPtr )
	{
		delete s_logListPtr;
	}
}